package com.lingtianyu.tech.erbaoshen.core.config;

import com.lingtianyu.tech.erbaoshen.core.consumer.service.GenericService;
import com.lingtianyu.tech.erbaoshen.core.provider.bean.ErBaoShenRpcServiceBeans;
import com.lingtianyu.tech.erbaoshen.core.provider.bean.ServiceBean;
import com.lingtianyu.tech.erbaoshen.core.provider.bean.annotation.ErBaoShenService;
import com.lingtianyu.tech.erbaoshen.core.provider.bean.annotation.Service;
import com.lingtianyu.tech.erbaoshen.core.provider.bean.registry.ScannerImportBeanDefinitionRegistrar;
import com.lingtianyu.tech.erbaoshen.core.util.KeyUtil;
import com.lingtianyu.tech.erbaoshen.core.util.SerializeUtil;
import com.lingtianyu.tech.erbaoshen.core.util.serialize.FastJsonSerializeExecute;
import com.lingtianyu.tech.erbaoshen.core.util.serialize.Hessian2SerializeExecute;
import com.lingtianyu.tech.erbaoshen.core.util.serialize.JacksonSerializeExecute;
import com.lingtianyu.tech.erbaoshen.core.util.serialize.SerializeExecute;
import com.lingtianyu.tech.springcloud.grayzone.grey.annotation.SpringCloudGrey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Configuration
@Slf4j
@Import(ScannerImportBeanDefinitionRegistrar.class)
public class ErBaoShenAutoConfig {
    @Bean(name = "erBaoShenRpcRestTemplate")
    @LoadBalanced
    @SpringCloudGrey
    public RestTemplate erBaoShenRpcRestTemplate() {
        return new RestTemplate();
    }

    @Bean(name = "erBaoShenRpcServiceBeans")
    public ErBaoShenRpcServiceBeans erBaoShenRpcServiceBeans(ServiceRegistry serviceRegistry, Registration registration, Environment env) {
        return new ErBaoShenRpcServiceBeans(serviceRegistry, registration, env);
    }

    @Bean(name = "erBaoShenGenericService")
    public GenericService genericService(@Qualifier("erBaoShenRpcRestTemplate") RestTemplate erBaoShenRpcRestTemplate, ErBaoShenRpcServiceBeans erBaoShenRpcServiceBeans, Environment env, DiscoveryClient discoveryClient, SerializeUtil serializeUtil) {
        return new GenericService(erBaoShenRpcRestTemplate, erBaoShenRpcServiceBeans, env, discoveryClient, serializeUtil);
    }

    @Bean(name = "erBaoShenFastJsonSerializeExecute")
    public SerializeExecute fastJsonSerializeExecute() {
        return new FastJsonSerializeExecute();
    }

    @Bean(name = "erBaoShenHessianSerializeExecute")
    public SerializeExecute hessian2SerializeExecute() {
        return new Hessian2SerializeExecute();
    }

    @Bean(name = "erBaoShenJacksonSerializeExecute")
    public SerializeExecute jacksonSerializeExecute() {
        return new JacksonSerializeExecute();
    }

    @Bean
    public SmartInitializingSingleton smartInitializingErBaoShenServiceBean(ErBaoShenRpcServiceBeans erBaoShenRpcServiceBeans) {
        return () -> {
            //加载Configuration 中的  provider 通过ServiceBean
            String[] beanNames = ErBaoShenRpcApplicationContextAware.getApplicationContext().getBeanNamesForType(ServiceBean.class);
            if (beanNames != null) {
                for (String beanName : beanNames) {
                    ServiceBean bean = (ServiceBean) ErBaoShenRpcApplicationContextAware.getApplicationContext().getBean(beanName);
                    String key = KeyUtil.getProviderKey(bean.getInterfaceClass().getTypeName(), bean.getGroup(), bean.getVersion());
                    erBaoShenRpcServiceBeans.putServiceBeanMap(key, bean, beanName);
                }
            }
            String[] servcieBeans = ErBaoShenRpcApplicationContextAware.getApplicationContext().getBeanNamesForAnnotation(Service.class);
            String[] erBaoShenServiceBeans = ErBaoShenRpcApplicationContextAware.getApplicationContext().getBeanNamesForAnnotation(ErBaoShenService.class);
            List<String> allBeans = new ArrayList<>(servcieBeans.length + erBaoShenServiceBeans.length);
            for (String servcieBean : servcieBeans) {
                allBeans.add(servcieBean);
            }
            for (String erBaoShenServiceBean : erBaoShenServiceBeans) {
                allBeans.add(erBaoShenServiceBean);
            }
            if (allBeans != null) {
                for (String beanName : allBeans) {
                    Object ref = ErBaoShenRpcApplicationContextAware.getApplicationContext().getBean(beanName);
                    Class<?> targetClass = AopUtils.getTargetClass(ref);
                    Service annotation = targetClass.getAnnotation(Service.class);
                    ErBaoShenService annotation2 = targetClass.getAnnotation(ErBaoShenService.class);
                    if (annotation == null && annotation2 == null) {
                        continue;
                    }
                    ServiceBean serviceBean = new ServiceBean();
                    serviceBean.setGroup(annotation != null ? annotation.group() : annotation2.group());
                    serviceBean.setVersion(annotation != null ? annotation.version() : annotation2.version());
                    serviceBean.setRef(ref);
                    if (!getInterfaceName(annotation, annotation2).isEmpty()) {
                        Class<?> aClass = null;
                        try {
                            aClass = Class.forName(getInterfaceName(annotation, annotation2));
                            serviceBean.setInterface(aClass);
                        } catch (ClassNotFoundException e) {
                            log.error(e.getMessage(), e);
                            System.exit(1);
                        }
                    } else {
                        Class<?> aClass = getInterfaceClass(annotation, annotation2);
                        if (aClass.equals(void.class)) {
                            Class<?>[] interfaces = ref.getClass().getInterfaces();
                            if (interfaces == null || interfaces.length == 0) {
                                log.error("error for @ErBaoShenService interfaceClass is null", new NullPointerException("error for @ErBaoShenService interfaceClass is null"));
                                System.exit(1);
                            }
                            aClass = interfaces[0];
                        }
                        serviceBean.setInterface(aClass);
                    }
                    String key = KeyUtil.getProviderKey(serviceBean.getInterfaceClass().getTypeName(), serviceBean.getGroup(), serviceBean.getVersion());
                    erBaoShenRpcServiceBeans.putServiceBeanMap(key, serviceBean, beanName);
                }
            }
        };
    }

    @Bean
    public SerializeUtil serializeUtil(List<SerializeExecute> serializeExecutes) {
        return new SerializeUtil(serializeExecutes);
    }

    private String getInterfaceName(Service service, ErBaoShenService erBaoShenService) {
        if (service != null) {
            return service.interfaceName();
        }
        return erBaoShenService.interfaceName();
    }

    private Class<?> getInterfaceClass(Service service, ErBaoShenService erBaoShenService) {
        if (service != null) {
            return service.interfaceClass();
        }
        return erBaoShenService.interfaceClass();
    }
}
